package com.chaos.auth.config.userdetails.service;

import cn.hutool.core.util.ObjectUtil;
import com.chaos.auth.api.enums.OpenTypeEnums;
import com.chaos.auth.api.enums.UserStatusEnums;
import com.chaos.auth.config.grant.converter.helper.OAuth2EndpointHelper;
import com.chaos.auth.config.grant.converter.para.AppOpenIdOAuth2ParameterNames;
import com.chaos.auth.config.userdetails.details.AppUserDetails;
import com.chaos.auth.config.userdetails.service.base.UserDetailsExtService;
import com.chaos.auth.service.third.wx.WxLoginThirdDto;
import com.chaos.auth.service.third.wx.WxThirdService;
import com.chaos.framework.model.dto.ID;
import com.chaos.framework.model.dto.result.data.DataResult;
import com.chaos.framework.model.enums.ResultEnum;
import com.chaos.framework.starter.helper.CheckHelper;
import com.chaos.system.api.data.TUserData;
import com.chaos.system.api.data.UserSessionKeyData;
import com.chaos.system.api.feign.UserFeign;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.DisabledException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;

import java.util.Map;

@Slf4j
@Component
public class AppByWxOpenIdDetailsService implements UserDetailsExtService {

    @Resource
    private UserFeign userFeign;
    @Resource
    private WxThirdService wxThirdService;
    @Value("${wx.appid:}")
    private String appid;
    @Value("${wx.secret:}")
    private String secret;

    @Override
    public UserDetails loadUserByCode(String code, Map<String, Object> additionalParameters) {

        String response = wxThirdService.jsCode2Session(appid, secret, code, "authorization_code");
        ObjectMapper objectMapper = new ObjectMapper();
        WxLoginThirdDto login = null;
        try {
            login = objectMapper.readValue(response, WxLoginThirdDto.class);
        } catch (JsonProcessingException e) {
            OAuth2EndpointHelper.throwError(ResultEnum.WRONG_OPEN_ID);
        }

        Long tenantId = (Long) additionalParameters.get(AppOpenIdOAuth2ParameterNames.TENANT_ID);

        String openId = login.getOpenid();
        String unionId = login.getUnionid();
        String sessionKey = login.getSession_key();

        if (StringUtils.isEmpty(openId)) {
            OAuth2EndpointHelper.throwError(ResultEnum.WRONG_OPEN_ID);
        }
        DataResult<TUserData> result = userFeign.selectByWxOpenId(openId, tenantId);
        CheckHelper.requireSuccess(result);
        TUserData user = result.getData();
        if (ObjectUtil.isNull(user)) {
            // 推荐人
            String referrer = (String) additionalParameters.get(AppOpenIdOAuth2ParameterNames.REFERRER);
            Long referrerLong = null;
            if (ObjectUtil.isNotEmpty(referrer)) {
                referrerLong = Long.parseLong(referrer);
            }
            // 注册来源
            String source = (String) additionalParameters.get(AppOpenIdOAuth2ParameterNames.SOURCE);
            user = TUserData.builder().openId(openId).unionId(unionId).status(UserStatusEnums.IN_USE.getCode()).referrer(referrerLong).source(source)
                    .openType(OpenTypeEnums.WX_OPEN.getCode()).build();
            DataResult<ID> idResult = userFeign.insertModel(user);
            CheckHelper.requireSuccess(idResult);
            CheckHelper.requireNotNull(idResult, "用户插入失败!");
            Long userId = idResult.getData().getId();
            user.setId(userId);
        }

        DataResult<ID> skResult = userFeign.insertModel(UserSessionKeyData.builder().userId(user.getId()).sessionKey(sessionKey).build());
        CheckHelper.requireSuccess(skResult, "SK插入失败!");
        AppUserDetails userDetails = new AppUserDetails(user);
        if (!userDetails.isEnabled()) {
            OAuth2EndpointHelper.throwError(ResultEnum.ACCOUNT_IS_NOT_ENABLED);
        }
        return userDetails;
    }


}
